﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using DaqConfigureTool;
using DaqConfigureTool.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Diagnostics;
using System.Drawing.Text;
using System.Linq;
using System.Net;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;

public enum ChannelType
{
    Voltage,
    Current,
    Resistance,
    Temperature,
    Humidity,
    Pressure,

    //NTC,
    //KThermoCouple,
    //JThermoCouple,
    //TThermoCouple,
    UserDefine,
}

public interface IDaq
{
    Task<ChannelModel[]> GetChannels();
    Task Run(CancellationToken token);
    void Stop1();
    double GetSampleRate();
}

public enum DaqWorkStatus
{
    [Display(Name = "未连接")]
    Disconnected,
    [Display(Name = "搜索中")]
    Searching,
    [Display(Name = "连接中")]
    Connectting,
    [Display(Name = "已连接")]
    Connected,
    [Display(Name = "运行中")]
    Running
}

public class DaqChartSeriesGroup
{
    public string Name { get; set; }
    public ObservableCollection<SeriesViewModel> Series { get; set; } = [];
    public DaqChartSeriesGroup(string name)
    {
        Name = name;
    }
}

public class DaqMeasureData
{
    public ChannelModel[] Channels { get; set; }
    public int[] RawValue { get; set; }
    public DateTime Time { get; set; }
}

struct DataPoint
{
    public DateTime Time;
    public double Value;
}
class PlotBuffer
{
    public string? Name { get; set; }
    public ConcurrentQueue<DataPoint> DataPoints { get; set; } = [];
}

public partial class ChannelDetail : ObservableObject
{
    [ObservableProperty]
    private string? name;
    [ObservableProperty]
    private double max;
    [ObservableProperty]
    private double min;
}

public class ChannelSettings : ObservableObject
{
    public int Index { get; set; }
    private bool status;
    [JsonPropertyName("status")]
    public bool Status
    {
        get { return status; }
        set
        {
            SetProperty(ref status, value);
            //Debug.WriteLine($"status={status}");
        }
    }
    private int digits;
    [JsonPropertyName("digits")]
    public int Digits
    {
        get { return digits; }
        set
        {
            SetProperty(ref digits, value);
        }
    }

    private int physicalType;
    [JsonPropertyName("physicalType")]
    public int PhysicalType
    {
        get { return physicalType; }
        set
        {
            SetProperty(ref physicalType, value);
        }
    }

    private string unit;
    [JsonPropertyName("unit")]
    public string Unit
    {
        get { return unit; }
        set
        {
            SetProperty(ref unit, value);
        }
    }

    private DaqColor color = new DaqColor(255, 0, 0);
    [JsonPropertyName("color")]
    public DaqColor Color
    {
        get { return color; }
        set
        {
            SetProperty(ref color, value);
        }
    }

    private double physicalMin;
    [JsonPropertyName("physicalMin")]
    public double PhysicalMin
    {
        get { return physicalMin; }
        set
        {
            SetProperty(ref physicalMin, value);
        }
    }

    private double physicalMax;
    [JsonPropertyName("physicalMax")]
    public double PhysicalMax
    {
        get { return physicalMax; }
        set
        {
            SetProperty(ref physicalMax, value);
        }
    }
    private string alias;
    [JsonPropertyName("alias")]
    public string Alias
    {
        get { return alias; }
        set
        {
            SetProperty(ref alias, value);
        }
    }
}

public class DaqSettings : ObservableObject
{
    private string version;
    [JsonPropertyName("version")]
    public string Version
    {
        get { return version; }
        set
        {
            SetProperty(ref version, value);
        }
    }
    private string sn;
    [JsonPropertyName("sn")]
    public string SN
    {
        get { return sn; }
        set
        {
            SetProperty(ref sn, value);
        }
    }
    private int channelCount;
    [JsonPropertyName("chCount")]
    public int ChannelCount
    {
        get { return channelCount; }
        set
        {
            SetProperty(ref channelCount, value);
        }
    }

    private ObservableCollection<ChannelSettings> channels;
    [JsonPropertyName("channels")]
    public ObservableCollection<ChannelSettings> Channels
    {
        get { return channels; }
        set
        {
            SetProperty(ref channels, value);
        }
    }

    private ObservableCollection<ChannelSettings> selectedChannels;
    [JsonIgnore]
    public ObservableCollection<ChannelSettings> SelectedChannels
    {
        get { return selectedChannels; }
        set
        {
            SetProperty(ref selectedChannels, value);
        }
    }
}

public abstract partial class DaqBase : ObservableRecipient
{
    public abstract Task GetChannelsAsync(CancellationToken token, List<int>? whiteList = null);
    public abstract Task<double> GetSampleRateAsync(CancellationToken token);
    public abstract Task OpenAsync(CancellationToken token);
    public abstract Task CloseAsync(CancellationToken token);
    public abstract Task<List<string>> SearchAsync(CancellationToken token);
    public abstract Task<int> FetchAsync(int timeout, CancellationToken token);
    public abstract Task StopAsync(CancellationToken token);
    public abstract Task SendDaqSettings(CancellationToken token);
    public abstract Task<bool> EnsureConnection(CancellationToken token);
    public abstract Task<bool> ModifyAddress(object address, CancellationToken token);

    private CancellationTokenSource tokenSource;
    //private ChannelModel[] Channels { get; set; }
    protected DaqMeasureData MeasureData { get; set; } = new();
    protected Queue<DaqMeasureData> MeasureDataQueue { get; set; } = new();
    protected ConcurrentQueue<DaqMeasureData> DatabaseMeasureDataQueue { get; set; } = new();

    [ObservableProperty]
    private ObservableCollection<ChannelModel> displayChannels = [];

    [ObservableProperty]
    private IPAddress? address;

    [ObservableProperty]
    private ObservableCollection<ChannelDetail> channelDetails;

    private DaqSettings daqSettings = new();
    public DaqSettings DaqSettings
    {
        get => daqSettings;
        set
        {
            SetProperty(ref daqSettings, value);
        }
    }

    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(StartCommand))]
    [NotifyCanExecuteChangedFor(nameof(StopCommand))]
    private DaqWorkStatus status;
    [ObservableProperty]
    private double sampleRate;


    private bool CanStart()
    {
        return Status == DaqWorkStatus.Disconnected;
    }
    private bool CanStop()
    {
        return Status == DaqWorkStatus.Running;
    }

    [ObservableProperty]
    private bool lockYAxes = true;
    public object ChartSync { get; } = new object();
    
    private static string Formatter(DateTime date)
    {
        var secsAgo = (DateTime.Now - date).TotalSeconds;
        return date.ToString("HH:mm:ss");
    }
    private double[] GetSeparators(DateTime start, DateTime end)
    {
        long speratorCount = 5;
        if (start >= end)
        {
            return new double[]
            {
                start.Ticks,
                end.Ticks
            };
        }

        long ticks = (end - start).Ticks;
        long interval = ticks / speratorCount;
        return new double[]
        {
            start.Ticks,
            start.Ticks + interval,
            start.Ticks + interval * 2,
            start.Ticks + interval * 3,
            start.Ticks + interval * 4,
            end.Ticks
        };
    }

    private async Task InitialChannels(CancellationToken token)
    {
        await GetChannelsAsync(token);
        //ChartSeriesData.Clear();

        var channels = MeasureData.Channels.Where(ch => ch.IsEnabled).ToList();

        //如果DisplayChannels不存在获取到的某个通道，则将这个通道加入到DisplayChannels
        foreach (var ch in channels)
        {
            if (!DisplayChannels.Any(c => c.Name == ch.Name))
            {
                DisplayChannels.Add(ch);
            }
        }

        //如果获取到的通道不存在DisplayChannels的某个通道，则将这个通道移出DisplayChannels
        if (DisplayChannels.Count > 0)
        {
            for (int i = DisplayChannels.Count - 1; i >= 0; i--)
            {
                var ch = DisplayChannels[i];
                if (!channels.Any(c => c.Name == ch.Name))
                {
                    DisplayChannels.Remove(ch);
                }
            }
        }

        ChannelDetails = [];
        foreach (var ch in DisplayChannels)
        {
            ChannelDetails.Add(new()
            {
                Name = ch.Name,
            });
            ch.Reset();
        }

        //DisplayChannels = new ObservableCollection<ChannelModel>(MeasureData.Channels.Where(ch => ch.IsEnabled).ToList());

        //InitChart(DisplayChannels);
        //foreach (var ch in MeasureData.Channels)
        //{
        //    string groupName = DaqDevice.GetTypeName(ch.Type);

        //    if (!MeasureChannelGroups.Any(t => t.Name == groupName))
        //    {
        //        MeasureChannelGroups.Add(new MeasureDataGroupModel()
        //        {
        //            Name = groupName
        //        });
        //    }
        //}
    }


    private readonly int dataDisplayUpdateIntervalInMillisecond = 10;
  

    private void PushData(string name, DateTime time, double value)
    {
        var queue = plotQueues.FirstOrDefault(x => x.Name == name);
        if (queue != null)
        {
            queue.DataPoints.Enqueue(new DataPoint
            {
                Time = time,
                Value = value
            });
        }
    }


    private List<PlotBuffer> plotQueues = [];
    private int plotDataCount = 0;

    [ObservableProperty]
    private TimeSpan elapsedTime = TimeSpan.Zero;

    private DateTime firstDateTime = DateTime.Now;
    [RelayCommand(CanExecute = nameof(CanStart))]
    private async Task Start()
    {
        Debug.WriteLine("Run start command");
        ElapsedTime = TimeSpan.Zero;

        if (Status != DaqWorkStatus.Disconnected) return;

        tokenSource = new CancellationTokenSource();
        var token = tokenSource.Token;

        Status = DaqWorkStatus.Connectting;
        //lock (ChartSync)
        //{
        //    for (int i = 0; i < _values.Count; i++)
        //    {
        //        var v = _values[i];
        //        v.Clear();
        //        v = null;
        //    }
        //    _values.Clear();
        //    _values = [];
        //}
        try
        {
            Debug.WriteLine("初始化设备");
            await OpenAsync(token);
            await StopAsync(token);
            await Task.Delay(100);
            await InitialChannels(token);
        }
        catch (Exception ex)
        {
            string error = $"设备初始化失败：{ex.Message}";
            Debug.WriteLine(error);
            try
            {
                await CloseAsync(token);
            }
            catch (Exception ex1)
            {
                Debug.WriteLine(ex1.Message);
            }
            Status = DaqWorkStatus.Disconnected;
            return;
        }

        Status = DaqWorkStatus.Running;
        int chIndex = 1;
        int refreshCount = 0;

        DatabaseMeasureDataQueue.Clear();
        MeasureDataQueue.Clear();

        var validChannels = DaqSettings.Channels.Where(ch => ch.Status).ToList();
        int validChannelsCount = validChannels.Count;
        Debug.WriteLine($"有效通道数：{validChannelsCount}");
        try
        {
            // await GetChannelsAsync();
            //await DataManagerViewModel.CreateDataReport(DateTime.Now, MeasureData.Channels);

            //获取采样率
            SampleRate = await GetSampleRateAsync(token);
            DateTime startTime = DateTime.Now;
            DateTime updateDisplayStartTime = DateTime.Now;

            double[] values = new double[validChannelsCount];
            double[] minValues = new double[validChannelsCount];
            double[] maxValues = new double[validChannelsCount];
            long[] sum = new long[validChannelsCount];
            double[] avg = new double[validChannelsCount];

            for (int i = 0; i < validChannelsCount; i++)
            {
                minValues[i] = double.PositiveInfinity;
                maxValues[i] = double.NegativeInfinity;
            }

            double value;
            int digits;
            bool firstData = true;
            Random _random = new();
            long dataCount = 0;
            int groupCount = 1;
            double fetchTime = SampleRate * groupCount;
            while (!token.IsCancellationRequested)
            {
                DateTime now = DateTime.Now;
                fetchTime = SampleRate * groupCount;
                //Debug.WriteLine("fetch=" + fetchTime);
                if (firstData || (now - startTime).TotalSeconds >= fetchTime)
                {
                    startTime = startTime.AddSeconds(fetchTime);
                    
                    //获取一次数据
                    groupCount = await FetchAsync(1000, token);
                    while (MeasureDataQueue.Count > 0)
                    {
                        dataCount++;
                        var data = MeasureDataQueue.Dequeue();
                        if (data.RawValue.Length != validChannels.Count) continue;
                        for (int i = 0; i < data.RawValue.Length; i++)
                        {
                            digits = validChannels[i].Digits;
                            value = data.RawValue[i];
                            sum[i] += data.RawValue[i];
                            avg[i] = Math.Round(sum[i] / dataCount / Math.Pow(10, digits), digits);
                            values[i] = Math.Round(value / Math.Pow(10, digits), digits);
                            minValues[i] = values[i] < minValues[i] ? values[i] : minValues[i];
                            maxValues[i] = values[i] > maxValues[i] ? values[i] : maxValues[i];
                            //PushData(validChannels[i].Alias, data.Time, values[i]);
                        }
                        if (firstData)
                        {
                            firstDateTime = data.Time;
                            firstData = false;
                        }
                        
                        //Debug.WriteLine(data.RawValue[0]);
                        //PushData(data.Time, values);

                        //Debug.WriteLine($"len:{data.RawValue.Length}");
                        DatabaseMeasureDataQueue.Enqueue(data);

                        
                    }
                }
                if ((now - updateDisplayStartTime).TotalMilliseconds >= dataDisplayUpdateIntervalInMillisecond)
                {
                    updateDisplayStartTime = now;

                    //ChartDataBuffer? chartDataBuffer = null;

                    //refreshCount++;

                    //lock (ChartSync)
                    //{
                    //    //DateTime t1 = DateTime.Now;
                    //    int bufferCount = buffer.Count;
                    //    Debug.WriteLine(bufferCount);
                    //    if (bufferCount > 0)
                    //    {
                            
                    //        if (bufferCount >= 300 && bufferCount < 1000)
                    //        {
                    //            bufferCount = 300;
                    //        }
                            
                    //        while (bufferCount-- > 0)
                    //        {
                    //            chartDataBuffer = PopData();
                    //            if (chartDataBuffer != null)
                    //            {
                    //                for (int i = 0; i < _values.Count(); i++)
                    //                {
                    //                    _values[i].AddLast(new DateTimePoint(chartDataBuffer.Time, chartDataBuffer.Values[i]));
                    //                    while (_values[i].Count > 10000) _values[i].RemoveFirst();
                    //                }
                    //                //Debug.WriteLine("更i性能数据");
                    //            }
                    //        }
                    //        _customAxis.CustomSeparators = GetSeparators(_values[0].First().DateTime, _values[0].Last().DateTime);
                    //    }
                    //    //Debug.WriteLine((DateTime.Now - t1).TotalMilliseconds);
                    //}

                    for (int i = 0; i < MeasureData.Channels.Length; i++)
                    {
                        MeasureData.Channels[i].Value = values[i];
                    }
                    for (int i = 0; i < validChannelsCount; i++)
                    {
                        DisplayChannels[i].Value = values[i];
                        DisplayChannels[i].Min = minValues[i];
                        DisplayChannels[i].Max = maxValues[i];
                        DisplayChannels[i].Average = avg[i];
                    }


                    //                  foreach (var group in MeasureChannelGroups)
                    //{
                    //	int index = 0;
                    //	foreach (var ch in group.Channels)
                    //	{
                    //		ch.Value = MeasureData.Channels[index++].Value;
                    //	}
                    //}
                }
                if(!firstData)
                {
                    ElapsedTime = DateTime.Now - firstDateTime;
                }
                await Task.Delay(1, token);
            }
        }
        catch (OperationCanceledException)
        {
            Debug.WriteLine("停止采集");
        }
        catch (Exception ex)
        {
            string error = $"异常退出：{ex.Message}";
            Debug.WriteLine(error);
        }

        try
        {
            Debug.WriteLine("关闭设备");
            await StopAsync(CancellationToken.None);
            await CloseAsync(CancellationToken.None);
        }
        catch (Exception ex)
        {
            string error = $"关闭失败：{ex.Message}";
            Debug.WriteLine(error);
        }
        tokenSource.Cancel();
        Status = DaqWorkStatus.Disconnected;
    }

    [RelayCommand(CanExecute = nameof(CanStop))]
    private void Stop()
    {
        this.tokenSource?.Cancel();
    }
}

public class ChartData
{
    public bool IsEnabled { get; set; }
    public double Value { get; set; }
    public DateTime Category { get; set; }
}

public class ChartDataGroup
{
    public string Name { get; set; }
    public string Unit { get; set; }
    public ObservableCollection<ChartData> Channels { get; set; } = [];
}

public class DataItem
{
    public string Category { get; set; }

    public double Value { get; set; }
}

public class SeriesViewModel
{
    public string SeriesType { get; set; }

    public ObservableCollection<DataItem> Items { get; set; } = [];

}

public class DaqDevice
{
    List<ChannelModel> Channels { get; set; }
    public static string GetDefaultUnit(ChannelType type)
    {
        return type switch
        {
            ChannelType.Voltage => "V",
            ChannelType.Current => "A",
            ChannelType.Temperature => "°C",
            ChannelType.Resistance => "Ω",
            ChannelType.Humidity => "%",
            ChannelType.Pressure => "kPa",
            ChannelType.UserDefine => "",
            _ => "",
        };
    }

    public static string GetTypeName(ChannelType type)
    {
        return type switch
        {
            ChannelType.Voltage => "电压",
            ChannelType.Current => "电流",
            ChannelType.Temperature => "温度",
            ChannelType.Resistance => "电阻",
            ChannelType.Humidity => "湿度",
            ChannelType.Pressure => "压力",
            ChannelType.UserDefine => "",
            _ => "",
        };
    }
    public static string GetTypeName(string unit)
    {
        var type = GetChannelType(unit);
        return type switch
        {
            ChannelType.Voltage => "电压",
            ChannelType.Current => "电流",
            ChannelType.Temperature => "温度",
            ChannelType.Resistance => "电阻",
            ChannelType.Humidity => "湿度",
            ChannelType.Pressure => "压力",
            ChannelType.UserDefine => "",
            _ => "",
        };
    }

    public static string[] GetUnits(ChannelType type)
    {
        return type switch
        {
            ChannelType.Voltage => ["nV", "uV", "mV", "V", "kV"],
            ChannelType.Current => ["nA", "uA", "mA", "A"],
            ChannelType.Resistance => ["uΩ", "mΩ", "Ω", "kΩ", "MΩ", "GΩ"],
            ChannelType.Temperature => ["°C"],
            ChannelType.Humidity => ["%"],
            ChannelType.Pressure => ["kPa", "MPa", "bar", "psi"],
            _ => [],
        };
    }

    public static ChannelType GetChannelType(string unit)
    {
        return unit switch
        {
            "nV" => ChannelType.Voltage,
            "uV" => ChannelType.Voltage,
            "mV" => ChannelType.Voltage,
            "V" => ChannelType.Voltage,
            "kV" => ChannelType.Voltage,

            "nA" => ChannelType.Current,
            "uA" => ChannelType.Current,
            "mA" => ChannelType.Current,
            "A" => ChannelType.Current,

            "uΩ" => ChannelType.Resistance,
            "mΩ" => ChannelType.Resistance,
            "Ω" => ChannelType.Resistance,
            "kΩ" => ChannelType.Resistance,
            "MΩ" => ChannelType.Resistance,
            "GΩ" => ChannelType.Resistance,

            "°C" => ChannelType.Temperature,
            "℃" => ChannelType.Temperature,

            "%" => ChannelType.Humidity,

            "kPa" => ChannelType.Pressure,
            "MPa" => ChannelType.Pressure,
            "bar" => ChannelType.Pressure,
            "psi" => ChannelType.Pressure,

            _ => ChannelType.Voltage
        };
    }
}
